﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using JpLabs.Geometry;
using System.Windows.Media.Animation;

namespace Duellum.Wpf2d.Plugin.Drawing
{
	public interface IDrawing2D
	{
		Rect Bounds { get; }
		void Render(DrawingContext dc);
	}

	public static class Drawing2DExt
	{
		static public void Render(this IDrawing2D drawing, OverlayVisual visual, PointInt? position)
		{
			if (drawing == null || position == null) {
				visual.Render( delegate{} );
			} else {
				PointInt pos = position.Value;
				Point p = Wpf2dPlugin.PositionToCenterPoint(pos.X, pos.Y);
				Transform t =	new TranslateTransform(p.X, p.Y);

				visual.Render(drawing.Render, t);
			}
		}

		static public void Render(this IDrawing2D drawing, OverlayVisual visual, PointInt? position, double rotation)
		{
			if (drawing == null || position == null) {
				visual.Render( delegate{} );
			} else {
				PointInt pos = position.Value;
				Point p = Wpf2dPlugin.PositionToCenterPoint(pos.X, pos.Y);
				Transform t =	new TranslateTransform(p.X, p.Y);

				Transform r = new RotateTransform(rotation * 180 / Math.PI);

				var transform = new TransformGroup() { Children = new TransformCollection( new[] { r, t } ) };
				
				visual.Render(drawing.Render, transform);
				//visual.Transform = t;
				//visual.Render(drawing.Render);
			}
		}
	}

	//internal class MyRandomAnim : ObjectAnimationBase
	//{
	//    private long nextTick;
	//    private object lastValue;
		
	//    public MyRandomAnim()
	//    {
	//        base.Duration = Duration.Forever;
	//    }
		
	//    protected override object GetCurrentValueCore(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
	//    {
	//        var thisTick = animationClock.CurrentTime.Value.Ticks;
			
	//        if (thisTick < nextTick) return lastValue;
			
	//        //animationClock.Controller.Stop();
			
	//        nextTick = thisTick + TimeSpan.TicksPerSecond * 10;
			
	//        var rnd = new Random();
			
	//        lastValue = new SolidColorBrush(Color.FromRgb((byte)rnd.Next(255), (byte)rnd.Next(255), (byte)rnd.Next(255)));
	//        return lastValue;
	//    }

	//    protected override Freezable CreateInstanceCore()
	//    {
	//        return new MyRandomAnim();
	//    }

	//    protected override Clock AllocateClock()
	//    {
	//        return base.AllocateClock();
	//    }
	//}
	
	[System.ComponentModel.ImmutableObject(true)]
	public class MapCursorDrawing : IDrawing2D
	{
		public const double DefaultThickness = 2;
		public const double DefaultRotationSpeed = 0;
		static public readonly Color DefaultBackCursorColor = Color.FromArgb(0x7F, 0x7F, 0x7F, 0x7F);
		
		public Brush ForeBrush		{ get; private set; }
		public Brush BackBrush		{ get; private set; }
		public double Thickness		{ get; private set; }
		public double RotationSpeed	{ get; private set; }

		private Pen backgroundPen;
		private Pen foregroundPen;

		public MapCursorDrawing(Color foreColor)
			: this(foreColor, DefaultThickness)
		{}

		public MapCursorDrawing(Color foreColor, double thickness)
			: this(foreColor, DefaultBackCursorColor, DefaultThickness)
		{}

		public MapCursorDrawing(Color foreColor, double thickness, double rotationSpeed)
			: this(foreColor, DefaultBackCursorColor, DefaultThickness, rotationSpeed)
		{}

		public MapCursorDrawing(Color foreColor, Color backColor)
			: this(foreColor, backColor, DefaultThickness)
		{}

		public MapCursorDrawing(Color foreColor, Color backColor, double thickness)
			: this(foreColor, backColor, thickness, DefaultRotationSpeed)
		{}
		
		public MapCursorDrawing(Color foreColor, Color backColor, double thickness, double rotationSpeed)
		{
			ForeBrush = new SolidColorBrush(foreColor);
			BackBrush = new SolidColorBrush(backColor);
			Thickness = thickness;
			RotationSpeed = rotationSpeed;
			InitPens();
		}

		public MapCursorDrawing(Brush foreBrush, Brush backBrush, double thickness, double rotationSpeed)
		{
			ForeBrush = foreBrush;
			BackBrush = backBrush;
			Thickness = thickness;
			RotationSpeed = rotationSpeed;
			InitPens();
		}
	
		Rect IDrawing2D.Bounds
		{
			get {
				var hexSize = Wpf2dPlugin.DefaultHexSize;
				
				return new Rect(
					-(hexSize.Width / 2), -(hexSize.Height / 2),
					hexSize.Width, hexSize.Height
				);
			}
		}

		void IDrawing2D.Render(DrawingContext dc)
		{
			Point p = new Point();

			var hexSize = Wpf2dPlugin.DefaultHexSize;
			double radius = hexSize.Height / 2;
				
			dc.DrawEllipse(null, backgroundPen, p, radius, radius);
			
			dc.DrawEllipse(null, foregroundPen, p, radius, radius);
		}
		
		private void InitPens()
		{
			this.backgroundPen = GetBackgroundPen();
			this.foregroundPen = GetForegroundPen();
		}
		
		private Pen GetBackgroundPen()
		{
			if (this.BackBrush == null) return null;
			return new Pen(this.BackBrush, this.Thickness);
		}
		
		private Pen GetForegroundPen()
		{
			if (this.ForeBrush == null) return null;
			
			var pen = new Pen(this.ForeBrush, this.Thickness) {
				DashStyle = new DashStyle(new double[]{2, 2}, 0),
				DashCap = PenLineCap.Round
			};
			
			if (this.RotationSpeed != 0) {
				double speed = this.RotationSpeed;
				double dashLength = pen.DashStyle.Dashes.Sum();
				
				var rotateAnim
					= (speed > 0)
					? new DoubleAnimation() {
						From = 0,
						To = dashLength,
						Duration = new Duration(TimeSpan.FromSeconds(2 / speed)),
						RepeatBehavior = RepeatBehavior.Forever
					}
					: new DoubleAnimation() {
						From = 0,
						To = -dashLength,
						Duration = new Duration(TimeSpan.FromSeconds(2 / -speed)),
						RepeatBehavior = RepeatBehavior.Forever
					};
				pen.DashStyle.BeginAnimation(DashStyle.OffsetProperty, rotateAnim);
				
				//pen.BeginAnimation(Pen.BrushProperty, new MyRandomAnim());
			}
			
			return pen;
		}
	}
}
